/*
 * command.c
 *
 *  Created on: 2019骞�8鏈�29鏃�
 *      Author: Roy
 */

#ifndef NOT_USE_DEBUG_OS

#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
#include <string.h>
#include "command.h"
#include "printk.h"
#include "exec_cmd.h"

static user_command_t *head_cmd = NULL;
static user_command_t *tail_cmd = NULL;

/*
 * Parse user command line
 */
void parseargs(char *argstr, int *argc_p, char **argv, char** resid)
{
    int argc = 0;
    char c;
    enum ParseState lastState = PS_WHITESPACE;

    /* tokenize the argstr */
    while ((c = *argstr) != 0) {
        enum ParseState newState;

        if (c == ';' && lastState != PS_STRING && lastState != PS_ESCAPE)
            break;

        if (lastState == PS_ESCAPE) {
            newState = stackedState;
        } else if (lastState == PS_STRING) {
            if (c == '"') {
                newState = PS_WHITESPACE;
                *argstr = 0;
            } else {
                newState = PS_STRING;
            }
        } else if ((c == ' ') || (c == '\t')) {
            /* whitespace character */
            *argstr = 0;
            newState = PS_WHITESPACE;
        } else if (c == '"') {
            newState = PS_STRING;
            *argstr++ = 0;
            argv[argc++] = argstr;
        } else if (c == '\\') {
            stackedState = lastState;
            newState = PS_ESCAPE;
        } else {
            /* token */
            if (lastState == PS_WHITESPACE) {
                argv[argc++] = argstr;
            }
            newState = PS_TOKEN;
        }

        lastState = newState;
        argstr++;
    }

#if 0 /* for debugging */
    {
        int i;
        putLabeledWord("parseargs: argc=", argc);
        for (i = 0; i < argc; i++) {
            putstr("   ");
            putstr(argv[i]);
            putstr("\r\n");
        }
    }
#endif
    argv[argc] = NULL;
    if (argc_p != NULL)
        *argc_p = argc;

    if (*argstr == ';') {
        *argstr++ = '\0';
    }
    *resid = argstr;
}

/*
 * 頃勳殧頃滉皜?
 */
void unparseargs(char *argstr, int argc, const char **argv)
{
    int i;
    for (i = 0; i < argc; i++) {
        if (argv[i] != NULL) {
            strcat(argstr, " ");
            strcat(argstr, argv[i]);
        }
    }
}

/*
 * Genernal interface
 */

/*
 * For (main) commands
 */

/* add user command */
void add_command(user_command_t *cmd)
{
    if (head_cmd == NULL) {
        head_cmd = tail_cmd = cmd;
    } else {
        tail_cmd->next_cmd = cmd;
        tail_cmd = cmd;
    }
    /*printk("Registered '%s' command\n", cmd->name);*/
}

/* find command */
user_command_t *find_cmd(const char *cmdname)
{
    user_command_t *curr;

    /* do da string compare for the first offset character of cmdstr
      against each number of the cmdlist */
    curr = head_cmd;
    while(curr != NULL) {
        if (strncmp(curr->name, cmdname, strlen(cmdname)) == 0)
            return curr;
        curr = curr->next_cmd;
    }
    return NULL;
}

/* execute a function */
void execcmd(int argc, const char **argv)
{
    user_command_t *cmd = find_cmd(argv[0]);

    if (cmd == NULL) {
        printk("Could not found '%s' command\n", argv[0]);
        printk("If you want to konw available commands, type 'help'\n");
        return;
    }
    /*printk("execcmd: cmd=%s, argc=%d\n", argv[0], argc);*/

    cmd->cmdfunc(argc, argv);
}

/* parse and execute a string */
void exec_string(char *buf)
{
    int argc;
    char *argv[128];
    char *resid;

    while (*buf) {
        memset(argv, 0, sizeof(argv));
        parseargs(buf, &argc, argv, &resid);
        if (argc > 0)
            execcmd(argc, (const char **)argv);
        buf = resid;
    }
}

/*
 * For sub-commands
 */
void execsubcmd(user_subcommand_t *cmds, int argc, const char **argv)
{

    while (cmds->name != NULL) {
        if (strncmp(argv[0], cmds->name, strlen(argv[0])) == 0) {
            /*printk("subexeccmd: cmd=%s, argc=%d\n", argv[0], argc);*/
            cmds->cmdfunc(argc, argv);
            return;
        }
        cmds++;
    }
    printk("Could not found '%s' sub-command\n", argv[0]);
}

void print_usage(char *strhead, user_subcommand_t *cmds)
{
    printk("Usage:\n");
    while (cmds->name != NULL) {
        if (strhead)
            printk("%s ", strhead);
        if (*cmds->helpstr)
            printk("%s\n", cmds->helpstr);
        cmds++;
    }
}

void invalid_cmd(const char *cmd_name, user_subcommand_t *cmds)
{
    printk("invalid '%s' command: wrong argumets\n", cmd_name);
    print_usage("  ", cmds);
}

/*
 * Define (basic) built-in commands
 */
#if 0

    "help [{cmds}] -- Help about help?"
    "boot [{cmds}] - Booting linux kernel"
    "call <addr> <args> -- Execute binaries"
    "dump <addr> <length> -- Display (hex dump) a range of memory."
    "flash [{cmds}]-- Manage Flash memory"
    "info -- Display vivi information"
    "load [{cmds}] -- Load a file"
    "mem -- Show info about memory"
    "reset -- Reset the System"
    "param [eval|show|save [-n]|reset]"
    "part [ help | add | delete | show | reset ] -- MTD partition"
    "test -- Test items"
#endif

/* help command */
void command_help(int argc, const char **argv)
{
    user_command_t *curr;

    /* help <command>. invoke <command> with 'help' as an argument */
    if (argc == 2) {
        if (strncmp(argv[1], "help", strlen(argv[1])) == 0) {
            printk("Are you kidding?\n");
            return;
        }
        argv[0] = argv[1];
        argv[1] = "help";
        execcmd(argc, argv);
        return;
    }

    printk("Usage:\n");
    curr = head_cmd;
    while(curr != NULL) {
        printk("   %s\n", curr->helpstr);
        curr = curr->next_cmd;
    }
}

user_command_t help_cmd = {
    "help",
    command_help,
    NULL,
    "help [{cmds}] \t\t\t-- Help about help?"
};
/* Register basic user commands */
int init_builtin_cmds(void)
{
    add_command(&help_cmd);
    init_cmd_cfg();     /* 鐢ㄦ埛鑷畾涔夌殑鍛戒护 */
    return 0;
}

#endif
